package worker

import (
	"gitee.com/wint/tge"
	"sync"
)

// 工人线程池，用于处理比较耗时的io操作或算法密集操作

const (
	FUNC_CHAN_NUM	= 20	// 工作函数信道缓冲大小
	WORKER_NUM		= 20	// 工人数量
)

// 工人线程
type Worker struct {
	tasks		chan func()	// 操作函数输入队列
	pool 		*WorkerPool
}

func (w *Worker) Excute(fn func()) {
	defer func() {
		if err := recover(); err != nil {
			if nil != w.pool.panicHandler {
				w.pool.panicHandler(w)
			} else {
				tge.Logger.Println(err)	
			}
		}
	} ()

	fn()
}

func NewWorker(pool *WorkerPool) *Worker {
	w := &Worker{make(chan func(), 1), pool}
	w.Run()
	return w
}

func (w *Worker) Run() {
	go func () {
		for fn := range w.tasks{
			if nil == fn {
				return
			}
			w.Excute(fn)
			w.pool.PutWorker(w)
		}
	} ()
}

// 线程池
type WorkerPool struct {
	sync.Mutex
	workers		[]*Worker 	// 空闲工人队列
	workerNum 	int 		// 工人的总数量
	tasks		chan func()	// 操作函数输入队列

	panicHandler	func(interface{})	// 崩溃处理函数
}

func NewWorkerPool(count int) *WorkerPool {
	pool := &WorkerPool{}
	pool.workers = make([]*Worker, 0, count)
	pool.tasks = make(chan func(), FUNC_CHAN_NUM)

	pool.Run()
	pool.AddWorkerCount(count)
	return pool
}

func (wp *WorkerPool) Run() {
	go func() {
		for fn := range wp.tasks {
			w := wp.GetWorker()
			w.tasks <- fn
		}
	} ()
}

func (wp *WorkerPool) PrintInfo() {
	wp.Lock()
	n := wp.workerNum
	freeN := len(wp.workers)
	wp.Unlock()
	tge.Logger.Println("WorkerPool total worker count", n, "free count", freeN)
}

func (wp *WorkerPool) GetWorker() *Worker {
	wp.Lock()
	n := len(wp.workers)
	var w *Worker = nil
	if n > 0 {
		w = wp.workers[n-1]
		wp.workers = wp.workers[:n-1]
	} else {
		w = NewWorker(wp)
		wp.workerNum++
	}
	wp.Unlock()
	return w
}

func (wp *WorkerPool) PutWorker(w *Worker) {
	wp.Lock()
	wp.workers = append(wp.workers, w)
	wp.Unlock()
}

func (wp *WorkerPool) RunWork(fn func()) {
	// if len(wp.tasks) >= FUNC_CHAN_NUM / 2 {
	// 	wp.AddWorkerCount(WORKER_NUM)
	// }
	wp.tasks <- fn
}

func (wp *WorkerPool) AddWorkerCount(count int) {
	wp.Lock()
	for i := 0; i < count; i++ {
		wp.workers = append(wp.workers, NewWorker(wp))
		wp.workerNum++
	}
	wp.Unlock()
}

var workerpool *WorkerPool = NewWorkerPool(WORKER_NUM)

func PrintInfo() {
	workerpool.PrintInfo()
}

func RunWork(fn func()) {
	workerpool.RunWork(fn)
}

func AddWorkerCount(count int) {
	workerpool.AddWorkerCount(count)
}

func CloseWork() {
	close(workerpool.tasks)
}